home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Utilities / Post / Source / SimpleRexx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-09  |  9.0 KB  |  398 lines

  1. /*
  2.  * Simple ARexx interface...
  3.  *
  4.  * This is a very "Simple" interface to the world of ARexx...
  5.  * For more complex interfaces into ARexx, it is best that you
  6.  * understand the functions that are provided by ARexx.
  7.  * In many cases they are more powerful than what is presented
  8.  * here.
  9.  *
  10.  * This code is fully re-entrant and self-contained other than
  11.  * the use of SysBase/AbsExecBase and the ARexx RVI support
  12.  * library which is also self-contained...
  13.  */
  14.  
  15. #include    <exec/types.h>
  16. #include    <exec/nodes.h>
  17. #include    <exec/lists.h>
  18. #include    <exec/ports.h>
  19. #include    <exec/memory.h>
  20.  
  21. #include    <proto/exec.h>
  22. #include    <proto/rexxsyslib.h>
  23. #include    <clib/alib_protos.h>
  24. #include    <rexx/storage.h>
  25. #include    <rexx/rxslib.h>
  26.  
  27. #include    <stdio.h>
  28. #include    <string.h>
  29. #include    <ctype.h>
  30.  
  31. #include    "SimpleRexx.h"
  32.  
  33. struct    Library    *RexxSysBase=NULL;
  34.  
  35. /*
  36.  * This function returns the port name of your ARexx port.
  37.  * It will return NULL if there is no ARexx port...
  38.  *
  39.  * This string is *READ ONLY*  You *MUST NOT* modify it...
  40.  */
  41. char *ARexxName(AREXXCONTEXT RexxContext)
  42. {
  43. register    char    *tmp=NULL;
  44.  
  45.     if (RexxContext) tmp=RexxContext->PortName;
  46.     return(tmp);
  47. }
  48.  
  49. /*
  50.  * This function returns the signal mask that the Rexx port is
  51.  * using.  It returns NULL if there is no signal...
  52.  *
  53.  * Use this signal bit in your Wait() loop...
  54.  */
  55. ULONG ARexxSignal(AREXXCONTEXT RexxContext)
  56. {
  57. register    ULONG    tmp=NULL;
  58.  
  59.     if (RexxContext) tmp=1L << (RexxContext->ARexxPort->mp_SigBit);
  60.     return(tmp);
  61. }
  62.  
  63. /*
  64.  * This function returns a structure that contains the commands sent from
  65.  * ARexx...  You will need to parse it and return the structure back
  66.  * so that the memory can be freed...
  67.  *
  68.  * This returns NULL if there was no message...
  69.  */
  70. struct RexxMsg *GetARexxMsg(AREXXCONTEXT RexxContext)
  71. {
  72. register    struct    RexxMsg    *tmp=NULL;
  73. register        short    flag;
  74.  
  75.     if (RexxContext)
  76.         if (tmp=(struct RexxMsg *)GetMsg(RexxContext->ARexxPort))
  77.     {
  78.         if (tmp->rm_Node.mn_Node.ln_Type==NT_REPLYMSG)
  79.         {
  80.             /*
  81.              * If we had sent a command, it would come this way...
  82.              *
  83.              * Since we don't in this simple example, we just throw
  84.              * away anything that looks "strange"
  85.              */
  86.             flag=FALSE;
  87.             if (tmp->rm_Result1) flag=TRUE;
  88.  
  89.             /*
  90.              * Free the arguments and the message...
  91.              */
  92.             DeleteArgstring(tmp->rm_Args[0]);
  93.             DeleteRexxMsg(tmp);
  94.             RexxContext->Outstanding-=1;
  95.  
  96.             /*
  97.              * Return the error if there was one...
  98.              */
  99.             tmp=flag ? REXX_RETURN_ERROR : NULL;
  100.         }
  101.     }
  102.     return(tmp);
  103. }
  104.  
  105. /*
  106.  * Use this to return a ARexx message...
  107.  *
  108.  * If you wish to return something, it must be in the RString.
  109.  * If you wish to return an Error, it must be in the Error.
  110.  * If there is an error, the RString is ignored.
  111.  */
  112. void ReplyARexxMsg(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
  113.             char *RString,LONG Error)
  114. {
  115.     if (RexxContext) if (rmsg) if (rmsg!=REXX_RETURN_ERROR)
  116.     {
  117.         rmsg->rm_Result2=0;
  118.         if (!(rmsg->rm_Result1=Error))
  119.         {
  120.             /*
  121.              * if you did not have an error we return the string
  122.              */
  123.             if (rmsg->rm_Action & (1L << RXFB_RESULT)) if (RString)
  124.             {
  125.                 rmsg->rm_Result2=(LONG)CreateArgstring(RString,
  126.                             (LONG)strlen(RString));
  127.             }
  128.         }
  129.  
  130.         /*
  131.          * Reply the message to ARexx...
  132.          */
  133.         ReplyMsg((struct Message *)rmsg);
  134.     }
  135. }
  136.  
  137. /*
  138.  * This function will set an error string for the ARexx
  139.  * application in the variable defined as <appname>.LASTERROR
  140.  *
  141.  * Note that this can only happen if there is an ARexx message...
  142.  *
  143.  * This returns TRUE if it worked, FALSE if it did not...
  144.  *
  145.  * This function now uses SetArexxVariable ;-) chris
  146.  */
  147.  
  148. short SetARexxLastError(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
  149.             char *ErrorString)
  150. {
  151.     return(SetARexxVariable(RexxContext, rmsg, RexxContext->ErrorName, ErrorString));
  152. }
  153.  
  154. /*
  155.  * This function will set a variable for the ARexx
  156.  * application in the variable defined as <appname>.variable
  157.  *
  158.  * Note that this can only happen if there is an ARexx message...
  159.  *
  160.  * This returns TRUE if it worked, FALSE if it did not...
  161.  *
  162.  * new function implemented by chris
  163.  */
  164.  
  165. short SetARexxVariable(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
  166.             char *variable, char *ValueString)
  167. {
  168. register    short    OkFlag=FALSE;
  169.  
  170.     if (RexxContext) if (rmsg) if (CheckRexxMsg((struct Message *)rmsg))
  171.     {
  172.         /*
  173.          * Note that SetRexxVar() has more than just a TRUE/FALSE
  174.          * return code, but for this "basic" case, we just care if
  175.          * it works or not.
  176.          */
  177.         if (!SetRexxVar((struct Message *) rmsg,variable,ValueString,
  178.                         (long)strlen(ValueString)))
  179.         {
  180.             OkFlag=TRUE;
  181.         }
  182.     }
  183.     return(OkFlag);
  184. }
  185.  
  186. /*
  187.  * This function will send a string to ARexx...
  188.  *
  189.  * The default host port will be that of your task...
  190.  *
  191.  * If you set StringFile to TRUE, it will set that bit for the message...
  192.  *
  193.  * Returns TRUE if it send the message, FALSE if it did not...
  194.  */
  195. short SendARexxMsg(AREXXCONTEXT RexxContext,char *RString,
  196.             short StringFile)
  197. {
  198. register    struct    MsgPort    *RexxPort;
  199. register    struct    RexxMsg    *rmsg;
  200. register        short    flag=FALSE;
  201.  
  202.     if (RexxContext) if (RString)
  203.     {
  204.         if (rmsg=CreateRexxMsg(RexxContext->ARexxPort,
  205.                     RexxContext->Extension,
  206.                     RexxContext->PortName))
  207.         {
  208.             rmsg->rm_Action=RXCOMM | (StringFile ?
  209.                             (1L << RXFB_STRING):0);
  210.             if (rmsg->rm_Args[0]=CreateArgstring(RString,
  211.                             (LONG)strlen(RString)))
  212.             {
  213.                 /*
  214.                  * We need to find the RexxPort and this needs
  215.                  * to be done in a Forbid()
  216.                  */
  217.                 Forbid();
  218.                 if (RexxPort=FindPort(RXSDIR))
  219.                 {
  220.                     /*
  221.                      * We found the port, so put the
  222.                      * message to ARexx...
  223.                      */
  224.                     PutMsg(RexxPort,(struct Message *)rmsg);
  225.                     RexxContext->Outstanding+=1;
  226.                     flag=TRUE;
  227.                 }
  228.                 else
  229.                 {
  230.                     /*
  231.                      * No port, so clean up...
  232.                      */
  233.                     DeleteArgstring(rmsg->rm_Args[0]);
  234.                     DeleteRexxMsg(rmsg);
  235.                 }
  236.                 Permit();
  237.             }
  238.             else DeleteRexxMsg(rmsg);
  239.         }
  240.     }
  241.     return(flag);
  242. }
  243.  
  244. /*
  245.  * This function closes down the ARexx context that was opened
  246.  * with InitARexx...
  247.  */
  248. void FreeARexx(AREXXCONTEXT RexxContext)
  249. {
  250. register    struct    RexxMsg    *rmsg;
  251.  
  252.     if (RexxContext)
  253.     {
  254.         /*
  255.          * Clear port name so it can't be found...
  256.          */
  257.         RexxContext->PortName[0]='\0';
  258.  
  259.         /*
  260.          * Clean out any outstanding messages we had sent out...
  261.          */
  262.         while (RexxContext->Outstanding)
  263.         {
  264.             WaitPort(RexxContext->ARexxPort);
  265.             while (rmsg=GetARexxMsg(RexxContext))
  266.             {
  267.                 if (rmsg!=REXX_RETURN_ERROR)
  268.                 {
  269.                     /*
  270.                      * Any messages that come now are blown
  271.                      * away...
  272.                      */
  273.                     SetARexxLastError(RexxContext,rmsg,
  274.                                 "99: Port Closed!");
  275.                     ReplyARexxMsg(RexxContext,rmsg,
  276.                             NULL,100);
  277.                 }
  278.             }
  279.         }
  280.  
  281.         /*
  282.          * Clean up the port and delete it...
  283.          */
  284.         if (RexxContext->ARexxPort)
  285.         {
  286.             while (rmsg=GetARexxMsg(RexxContext))
  287.             {
  288.                 /*
  289.                  * Any messages that still are coming in are
  290.                  * "dead"  We just set the LASTERROR and
  291.                  * reply an error of 100...
  292.                  */
  293.                 SetARexxLastError(RexxContext,rmsg,
  294.                             "99: Port Closed!");
  295.                 ReplyARexxMsg(RexxContext,rmsg,NULL,100);
  296.             }
  297.             DeletePort(RexxContext->ARexxPort);
  298.         }
  299.  
  300.         /*
  301.          * Make sure we close the library...
  302.          */
  303.         if (RexxSysBase)
  304.         {
  305.             CloseLibrary(RexxSysBase);
  306.         }
  307.  
  308.         /*
  309.          * Free the memory of the RexxContext
  310.          */
  311.         FreeMem(RexxContext,sizeof(struct ARexxContext));
  312.     }
  313. }
  314.  
  315. /*
  316.  * This routine initializes an ARexx port for your process
  317.  * This should only be done once per process.  You must call it
  318.  * with a valid application name and you must use the handle it
  319.  * returns in all other calls...
  320.  *
  321.  * NOTE:  The AppName should not have spaces in it...
  322.  *        Example AppNames:  "MyWord" or "FastCalc" etc...
  323.  *        The name *MUST* be less that 16 characters...
  324.  *        If it is not, it will be trimmed...
  325.  *        The name will also be UPPER-CASED...
  326.  *
  327.  * NOTE:  The Default file name extension, if NULL will be
  328.  *        "rexx"  (the "." is automatic)
  329.  */
  330. AREXXCONTEXT InitARexx(char *AppName,char *Extension)
  331. {
  332. register    AREXXCONTEXT    RexxContext=NULL;
  333. register    short        loop;
  334. register    short        count;
  335. register    char        *tmp;
  336.  
  337.     if (RexxContext=AllocMem(sizeof(struct ARexxContext),
  338.                     MEMF_PUBLIC|MEMF_CLEAR))
  339.     {
  340.         if (RexxSysBase=OpenLibrary("rexxsyslib.library",
  341.                                 NULL))
  342.         {
  343.             /*
  344.              * Set up the extension...
  345.              */
  346.             if (!Extension) Extension="rexx";
  347.             tmp=RexxContext->Extension;
  348.             for (loop=0;(loop<7)&&(Extension[loop]);loop++)
  349.             {
  350.                 *tmp++=Extension[loop];
  351.             }
  352.             *tmp='\0';
  353.  
  354.             /*
  355.              * Set up a port name...
  356.              */
  357. /* I changed this from <appname>1 to <appname>.1; chris */
  358.             tmp=RexxContext->PortName;
  359.             for (loop=0;(loop<15)&&(AppName[loop]);loop++)
  360.             {
  361.                 *tmp++=toupper(AppName[loop]);
  362.             }
  363.             *tmp++='.';
  364.             *tmp='\0';
  365.  
  366.             /*
  367.              * Set up the last error RVI name...
  368.              *
  369.              * This is <appname>.LASTERROR
  370.              */
  371.             strcpy(RexxContext->ErrorName,RexxContext->PortName);
  372.             strcat(RexxContext->ErrorName,"LASTERROR");
  373.  
  374.             /* We need to make a unique port name... */
  375.             Forbid();
  376.             for (count=1,RexxContext->ARexxPort=(VOID *)1;
  377.                         RexxContext->ARexxPort;count++)
  378.             {
  379.                 sprintf(tmp, "%d", count);
  380.                 RexxContext->ARexxPort=
  381.                         FindPort(RexxContext->PortName);
  382.             }
  383.  
  384.             RexxContext->ARexxPort=CreatePort(
  385.                         RexxContext->PortName,NULL);
  386.             Permit();
  387.         }
  388.  
  389.         if (    (!(RexxSysBase))
  390.              ||    (!(RexxContext->ARexxPort))    )
  391.         {
  392.             FreeARexx(RexxContext);
  393.             RexxContext=NULL;
  394.         }
  395.     }
  396.     return(RexxContext);
  397. }
  398.